package com.sikaryofficial.backend.manager.information;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sikaryofficial.backend.constant.ArticleAuditStatusEnum;
import com.sikaryofficial.backend.constant.GuideTaskEnum;
import com.sikaryofficial.backend.constant.MyStatisticsTypeEnum;
import com.sikaryofficial.backend.domain.dto.req.information.ArticleEvaluateListReq;
import com.sikaryofficial.backend.domain.dto.req.information.ArticleEvaluateReq;
import com.sikaryofficial.backend.domain.dto.req.points.GuideTaskReq;
import com.sikaryofficial.backend.domain.dto.resp.information.ArticleEvaluateDTO;
import com.sikaryofficial.backend.domain.dto.resp.information.ArticleEvaluateReplyDTO;
import com.sikaryofficial.backend.domain.entity.ArticleEvaluate;
import com.sikaryofficial.backend.domain.mapping.ArticleEvaluateMapping;
import com.sikaryofficial.backend.domain.vo.EvaluateReplyCount;
import com.sikaryofficial.backend.domain.vo.ObjectCount;
import com.sikaryofficial.backend.service.IArticleEvaluateReplyService;
import com.sikaryofficial.backend.service.IArticleEvaluateService;
import com.sikaryofficial.backend.service.IArticleService;
import com.sikaryofficial.backend.service.IAttachmentService;
import com.sikaryofficial.backend.service.IMyStatisticsService;
import com.sikaryofficial.backend.service.IPointsDetailStrategy;
import com.sikaryofficial.backend.service.guidetask.GuideTaskProcess;
import com.sikaryofficial.backend.service.statistics.MyStatisticsEvent;
import com.sikaryofficial.backend.service.statistics.MyStatisticsProcessor;
import com.sikaryofficial.backend.service.user.UserCacheService;
import com.sikaryofficial.backend.service.useraction.cache.UserActionCacheService;
import com.sikaryofficial.common.core.constant.PointRuleConstant;
import com.sikaryofficial.common.core.domain.R;
import com.sikaryofficial.common.core.exception.ServiceException;
import com.sikaryofficial.common.security.utils.SecurityUtils;
import com.sikaryofficial.system.api.RemoteArticleService;
import com.sikaryofficial.system.api.model.att.AttachmentResp;
import com.sikaryofficial.system.api.model.infomation.ArticleDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author : qinjinyuan
 * @desc :  文章数据同步管理类
 * @date : 2024/03/13 11:50
 */
@Component
@Slf4j
public class ArticleEvaluateManager {
    @Autowired
    private IArticleEvaluateService articleEvaluateService;
    @Autowired
    private IArticleService articleService;

    @Autowired
    private UserCacheService userCacheService;
    @Autowired
    private IMyStatisticsService myStatisticsService;
    @Autowired
    private UserActionCacheService userActionCacheService;
    @Autowired
    private MyStatisticsProcessor myListener;
    @Autowired
    private IAttachmentService attachmentService;
    @Autowired
    private IArticleEvaluateReplyService replyService;
    @Value("${hismk.backend.article.reply.pageSize}")
    private Integer limitNum;
    @Autowired
    private RemoteArticleService remoteArticleService;
    @Resource
    private Map<String, IPointsDetailStrategy> pointsDetailStrategyMap;
    @Autowired
    private GuideTaskProcess guideTaskProcess;

    /**
     * 保存文章评价
     *
     * @param req
     * @return
     */
    public ArticleEvaluateDTO save(ArticleEvaluateReq req) {
        Long userId = SecurityUtils.getUserId();
        // 数据检查
        beforeCheckData(req);
        // 数据保存
        ArticleEvaluateDTO articleEvaluateDTO = articleEvaluateService.saveEvaluate(req);
        IPointsDetailStrategy pointsDetailStrategy = pointsDetailStrategyMap.get(PointRuleConstant.ARTICLE_EVALUATE + IPointsDetailStrategy.SUFFIX);
        if (Objects.nonNull(articleEvaluateDTO)) {
            // 填充头像数据
            articleEvaluateDTO.setAvatar(userCacheService.getSignUserAvatar(articleEvaluateDTO.getCreatedBy()));
            // 填充昵称
            articleEvaluateDTO.setNickName(userCacheService.getSignUserNickName(articleEvaluateDTO.getCreatedBy()));
            // 保存附件信息
            attachmentService.saveAttachmentList(articleEvaluateDTO.getArticleEvaluateId(), req.getAttachmentList(), SecurityUtils.getUserId());
            // 评价获取积分
            // 如果 article.getHeadline() 字符串长度超过50 ，需要截取导50
            pointsDetailStrategy.updatePoints(articleEvaluateDTO.getArticleEvaluateId(), userId);
            // 在任意的story/reels/post发布评论可以触发完成指引任务
            if (Objects.nonNull(req.getHasGuideTask())
                    && Boolean.TRUE.equals(req.getHasGuideTask())
            ) {
                String taskCode = GuideTaskEnum.LEAVE_COMMENTS.getTaskCode();
                GuideTaskReq guideTaskReq = new GuideTaskReq(taskCode, userId);
                guideTaskProcess.processGuideTask(guideTaskReq);
            }
        }

        // 3.1 添加文章评价统计
        myListener.addMyStatistics(new MyStatisticsEvent(MyStatisticsTypeEnum.COMMENTS_ARTICLE.getBusinessType(), userId, req.getArticleEvaluateId()));
        // 3.2 添加该文章评论对应的评论统计
        myListener.addMyStatistics(new MyStatisticsEvent(MyStatisticsTypeEnum.COMMENTS_ARTICLE_COUNT.getBusinessType(), userId, req.getArticleId()));

        return articleEvaluateDTO;
    }

    private void beforeCheckData(ArticleEvaluateReq req) {
        R<ArticleDTO> sourceR = remoteArticleService.getSimpleInfo(req.getArticleId());
        if (Objects.isNull(sourceR) || Objects.isNull(sourceR.getData())) {
            throw new ServiceException("the article is empty");
        }
        ArticleDTO source = sourceR.getData();
        if (!ArticleAuditStatusEnum.APPROVED.getCode().equals(source.getAuditStatus())) {
            throw new ServiceException("evaluate only at the pass status article");
        }
    }

    /**
     * 获取文章评价详情及用户行为数据
     *
     * @param articleEvaluateId
     * @return
     */
    public ArticleEvaluateDTO getInfo(Long articleEvaluateId) {
        ArticleEvaluate articleEvaluate = articleEvaluateService.getById(articleEvaluateId);
        if (Objects.isNull(articleEvaluate)) {
            return null;
        }
        ArticleEvaluateDTO evaluateDTO = ArticleEvaluateMapping.INSTANCE.coverToDTO(articleEvaluate);
        // 评价图像
        evaluateDTO.setAvatar(userCacheService.getSignUserAvatar(articleEvaluate.getCreatedBy()));
        evaluateDTO.setNickName(userCacheService.getSignUserNickName(articleEvaluate.getCreatedBy()));
        // 获取附件信息
        evaluateDTO.setAttachmentList(attachmentService.getAttachmentById(articleEvaluateId));
        List<ArticleEvaluateDTO> list = Lists.newArrayList();
        list.add(evaluateDTO);
        buildUserActionData(list);
        return list.iterator().next();
    }

    /**
     * 获取文章评价列表及用户行为数据
     *
     * @param req
     * @return
     */
    public IPage<ArticleEvaluateDTO> listPage(ArticleEvaluateListReq req) {
        if ((Objects.nonNull(req.getArticleId()) && req.getArticleId() <= 0)) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        Page<ArticleEvaluateDTO> customerPage = new Page<>(req.getPageNum(), req.getPageSize());
        // 1、分页查询数据
        IPage<ArticleEvaluateDTO> evaluateDTOIPage = articleEvaluateService.evaluateList(customerPage, req);
        List<ArticleEvaluateDTO> evaluateRecords = evaluateDTOIPage.getRecords();
        if (CollUtil.isEmpty(evaluateRecords)) {
            return new Page<>(req.getPageNum(), req.getPageSize(), 0);
        }
        buildExtendData(evaluateRecords);
        // 5-填充回复列表第1页数据 及 回复总数
        buildReplyData(evaluateRecords);
        return evaluateDTOIPage;
    }

    private void buildReplyData(List<ArticleEvaluateDTO> evaluateRecords) {
        // 3、填充回复总数
        List<Long> evaluateIds = evaluateRecords.stream().map(ArticleEvaluateDTO::getArticleEvaluateId).collect(Collectors.toList());
        List<EvaluateReplyCount> evaluateReplyCountList = replyService.countByEvaluateId(evaluateIds);
        Map<Long, Integer> evaluateReplyCountMap = evaluateReplyCountList.stream().filter(item -> Objects.nonNull(item.getReplyCount()))
                .collect(Collectors.toMap(EvaluateReplyCount::getEvaluateId, EvaluateReplyCount::getReplyCount, (k1, k2) -> k1));
        evaluateRecords.forEach(item -> item.setReplyCount(MapUtils.getObject(evaluateReplyCountMap, item.getArticleEvaluateId())));

        // 填充每条评论下 回复列表的第1页数据-7条
        List<ArticleEvaluateReplyDTO> replyList = replyService.queryByEvaluateId(evaluateIds, limitNum);
        Map<Long, List<ArticleEvaluateReplyDTO>> replyListMap = replyList.stream().collect(Collectors.groupingBy(ArticleEvaluateReplyDTO::getArticleEvaluateId));
        evaluateRecords.forEach(item -> item.setReplyList(MapUtils.getObject(replyListMap, item.getArticleEvaluateId())));
    }

    private void buildExtendData(List<ArticleEvaluateDTO> evaluateRecords) {
        // 1、填充回复总数&点赞总数
        buildUserActionData(evaluateRecords);
        // 2、填充附件
        List<Long> evaluateIds = evaluateRecords.stream().map(ArticleEvaluateDTO::getArticleEvaluateId).collect(Collectors.toList());
        Map<Long, List<AttachmentResp>> attachmentMap = attachmentService.getAttachmentByIds(evaluateIds);
        // 3、填充头像数据
        Map<Long, String> userAvatarMap = userCacheService.getMultiUserAvatar(evaluateRecords.stream().map(ArticleEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        // 填充昵称
        Map<Long, String> userNickNameMap = userCacheService.getMultiUserNickName(evaluateRecords.stream().map(ArticleEvaluateDTO::getCreatedBy).collect(Collectors.toList()));
        evaluateRecords.forEach(item -> {
            item.setAttachmentList(attachmentMap.get(item.getArticleEvaluateId()));
            item.setAvatar(MapUtils.getString(userAvatarMap, item.getCreatedBy(), ""));
            item.setNickName(MapUtils.getString(userNickNameMap, item.getCreatedBy(), ""));
        });
    }

    /**
     * 构建评价的点赞统计及个人点赞数据
     *
     * @param result
     */
    public void buildUserActionData(List<ArticleEvaluateDTO> result) {
        if (CollUtil.isEmpty(result)) {
            return;
        }
        try {
            // 填充每条跟评对应的点赞数量
            processArticleData(result);
            // 是否自己点赞
            result.stream().filter(Objects::nonNull).forEach(this::checkUserActions);
        } catch (NullPointerException e) {
            log.error("Null pointer exception occurred. Possibly due to null element in the result list or null context in processing.", e);
        } catch (IllegalArgumentException e) {
            log.error("Illegal argument exception occurred. Check the validity of the input data.", e);
        } catch (Exception e) {
            // 捕获其他未预期的异常
            log.error("Unexpected exception occurred during processing: {}", e.getMessage(), e);
        }
    }

    private void processArticleData(List<ArticleEvaluateDTO> result) {
        // 点赞数量填充
        List<ObjectCount> objectCountList = myStatisticsService.countByObjectIds(result.stream().map(ArticleEvaluateDTO::getArticleEvaluateId).collect(Collectors.toList()));
        Map<Long, List<ObjectCount>> objectCountMap = objectCountList.stream().collect(Collectors.groupingBy(ObjectCount::getObjectId));
        result.forEach(replyDTO -> processCountData(replyDTO, objectCountMap));
    }

    private void processCountData(ArticleEvaluateDTO replyDTO, Map<Long, List<ObjectCount>> objectCountMap) {
        List<ObjectCount> objectCounts = MapUtils.getObject(objectCountMap, replyDTO.getArticleEvaluateId());
        if (CollUtil.isNotEmpty(objectCounts)) {
            populateLikesCount(replyDTO, objectCounts);
            populateReplyCount(replyDTO, objectCounts);
        }
    }

    private void populateLikesCount(ArticleEvaluateDTO replyDTO, List<ObjectCount> objectCounts) {
        objectCounts.stream()
                .filter(e -> MyStatisticsTypeEnum.LIKES_ARTICLE_EVALUATE.getBusinessType().equals(e.getBusinessType()))
                .findFirst()
                .ifPresent(e -> replyDTO.setLikesCount(e.getObjectCount()));
    }

    private void populateReplyCount(ArticleEvaluateDTO replyDTO, List<ObjectCount> objectCounts) {
        objectCounts.stream()
                .filter(e -> MyStatisticsTypeEnum.COMMENTS_ARTICLE_REPLAY_COUNT.getBusinessType().equals(e.getBusinessType()))
                .findFirst()
                .ifPresent(e -> replyDTO.setReplyCount(e.getObjectCount()));
    }

    private void checkUserActions(ArticleEvaluateDTO item) {
        if (Objects.nonNull(item.getLikesCount()) && item.getLikesCount() > 0) {
            item.setHasOwnerLikes(userActionCacheService.getOwnerAction(SecurityUtils.getUserId(), item.getArticleEvaluateId(),
                    MyStatisticsTypeEnum.LIKES_ARTICLE_EVALUATE.getBusinessType()));
        }
    }
}
